# install new packages IN THE CONSOLE!
install.packages("pacman")Datenimport
Einlesen von Datendateien
Wiederholung
Letzte Woche haben wir…
- den Unterschied zwischen numerischen und kategorialen Datentypen gelernt
- haben wir unsere ersten Diagramme mit
ggplot2erstellt - gelernt, welche Diagramme für verschiedene Datentypen geeignet sind
Heutige Ziele
Heute werden wir…
- lernen, wie man einen neuen Datensatz in Augenschein nimmt
- lernen, wie man verschiedene Datentypen importiert
- lernen, wie man Daten von Hand eingibt
- einen neuen Datensatz visualisieren
Lust auf mehr?
1 Daten erforschen
- letzte Woche haben wir mit Daten aus dem R-Paket
palmerpenguingsgearbeitet- Daten aus Paketen sind ein guter Weg, um Data Science Tools zu lernen
- aber ihr werdet irgendwann mit euren eigenen Daten arbeiten wollen
- Heute lernen wir die Grundlagen des Einlesens von Datendateien in R
1.1 Pakete
# load packages
pacman::p_load("tidyverse", # wrangling
"janitor", # wrangling
"here", # relative file paths
"patchwork" # plot layout
)wir werden mit dem Paket
pacmanbeginnen- die Funktion
p_load()nimmt Paketnamen als Argumente - sie prüft dann, ob wir das Paket installiert haben
- wenn ja, dann lädt sie das Paket
- wenn nicht, wird das Paket installiert und geladen
- die Funktion
dies erspart uns, jedes Mal neue Pakete zu installieren
wir haben jetzt
tidyverseundpatchworkgeladen und die neuen Paketejanitorundhereinstalliert und geladen
1.2 Dateien
- Speichert die Dateien unter ‘daten’ in den Moodle-Materialien für diese Woche
- Speichert die Dateien im Ordner
datenin eurem .RProj für diesen Kurs!
1.3 Eingebaute Daten
- Lasst uns zunächst einige eingebaute Daten untersuchen: den
iris-Datensatz- wie viele Variablen gibt es?
- wie viele Beobachtungen?
# load tidyverse
library(tidyverse)
# read-in iris dataset
data("iris")- iris = Iris
- petal = Blumenblatt
- sepal = Kelchblatt
1.4 Einen Datensatz erforschen
view(): Datensatz öffnen- Führt dies nur in der Konsole aus! Euer Dokument wird nicht gerendert, wenn ihr es in eurem Skript habt
- die Funktion
head()gibt die ersten 6 Zeilen der Daten aus
# print dataset (first 6 rows)
head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
1.4.1 glimpse()
- EN: glimpse = DE: Einblick
- aus dem Paket
tibble - gibt eine seitliche Vorschau des Datenrahmens
glimpse(iris)Rows: 150
Columns: 5
$ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
$ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
$ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
$ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
$ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
# print dataset (first 6 rows)
head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
1.4.2 summary()
- druckt eine Zusammenfassung für jede Variable
- Minimum, Maximum, Mittelwert von numerischen Variablen
- Anzahl der Beobachtungen pro Stufe einer kategorischen Variable
table1
Beispiel 1
- Versuch, den eingebauten Datensatz
table1zu laden - Untersuche den Datensatz mit den Funktionen, die wir gerade gelernt haben
- Gibt es irgendetwas Komisches in der Zusammenfassung? Wie könnten wir das beheben?
2 Daten importieren
wir wollen normalerweise mit unseren eigenen Daten arbeiten, nicht mit eingebauten Spielzeugdaten
wir konzentrieren uns nur auf rechteckige Daten (d. h. aufgeräumte Daten)
Es gibt viele verschiedene Dateitypen, die Daten annehmen können, z. B.
.xlsx,.txt,.csv,.tsvcsvist der am häufigsten verwendete Dateityp: Kommagetrennte Werte (EN:CommaSeparatedValue)- Versucht,
.xlsxzu vermeiden; wenn ihr einen Excel-Datensatz habt, versucht, ihn als.csvzu speichern, bevor ihr ihn in R lest
- Versucht,
- So sieht eine einfache CSV-Datei aus
Student ID,Full Name,favourite.food,mealPlan,AGE
1,Sunil Huffmann,Strawberry yoghurt,Lunch only,4
2,Barclay Lynn,French fries,Lunch only,5
3,Jayendra Lyne,N/A,Breakfast and lunch,7
4,Leon Rossini,Anchovies,Lunch only,
5,Chidiegwu Dunkel,Pizza,Breakfast and lunch,five
6,Güvenç Attila,Ice cream,Lunch only,6
die erste Zeile (die “Kopfzeile”) enthält die Spaltennamen
die folgenden Zeilen enthalten die Daten
Wie viele Variablen gibt es? Wie viele Beobachtungen?
2.1 readr Paket
- dieselben Daten können als Tabelle angezeigt werden, so wie wir es mit
penguinsundirisgemacht haben- aber zuerst müssen wir die Daten einlesen
- das
readrPaket (Teil vontidyverse) kann die meisten Datentypen einlesen
read_csv(here::here("daten", "students.csv"))| Student ID | Full Name | favourite.food | mealPlan | AGE |
|---|---|---|---|---|
| 1 | Sunil Huffmann | Strawberry yoghurt | Lunch only | 4 |
| 2 | Barclay Lynn | French fries | Lunch only | 5 |
| 3 | Jayendra Lyne | N/A | Breakfast and lunch | 7 |
| 4 | Leon Rossini | Anchovies | Lunch only | NA |
| 5 | Chidiegwu Dunkel | Pizza | Breakfast and lunch | five |
| 6 | Güvenç Attila | Ice cream | Lunch only | 6 |
2.2 here Paket
- Woher weiß R genau, wo der Ordner “Daten” zu finden ist?
- unser Arbeitsverzeichnis ist auf den Ort unseres RProjekts auf unserem Computer festgelegt
- Wann immer wir auf Daten in unserem RProjekt zugreifen wollen, sollten wir
here::here()verwenden. - um zu sehen, von wo aus
here()startet, führthere()aus
here()[1] "/Users/danielapalleschi/Documents/IdSL/Teaching/SoSe23/BA/ba_daten"
- dies wird auf allen unseren Rechnern anders aussehen
- Was jedoch gleich sein sollte, ist unsere Ordnerstruktur innerhalb unserer Projekte (z. B.
daten/students.csv).
- Was jedoch gleich sein sollte, ist unsere Ordnerstruktur innerhalb unserer Projekte (z. B.
here Paket
Vor dem here-Paket mussten wir R explizit mitteilen, wo sich eine Datei auf unserem Computer befindet (z.B., /Users/danielapalleschi/Documents/IdSL/Teaching/SoSe23/BA/ba_daten/daten/students.csv), oder die Funktion setwd() (set Working Directory) benutzen, um R mitzuteilen, wo alle Dateien zu finden sind (z.B. setwd(/Users/danielapalleschi/Documents/IdSL/Teaching/SoSe23/BA/ba_daten)). Glücklicherweise brauchen wir diese absoluten Dateipfade oder setwd() nie zu verwenden!
Aus der here-Paketdokumentation:
The goal of the here package is to enable easy file referencing in project-oriented workflows. In contrast to using
setwd(), which is fragile and dependent on the way you organize your files, here uses the top-level directory of a project to easily build paths to files.
Das bedeutet, dass wir nun den großen Vorteil haben, dass wir unseren Projektordner überall hin verschieben können und unser Dateipfad immer noch relativ zu dem Ort ist, an den wir unseren Projektordner verschoben haben. Das bedeutet, dass das Projekt unabhängig davon läuft, wo es sich auf eurem Computer befindet. Ihr könnt auch jemandem den Projektordner schicken, und alles sollte auf dessen Rechner laufen!
table1
Beispiel 2
- Importiert den Datensatz
students.csvund speichert ihn als Objekt mit dem Namendf_students.df_ist die Abkürzung für DataFrame; es ist eine gute Idee, ein Präfix vor Objektnamen zu verwenden, damit wir wissen, was jedes Objekt enthält.
- Beim Importieren von Daten mit
read_csvwerden einige Informationen in der Konsole ausgegeben. Was wird gedruckt? - Untersucht den Datensatz mit den Funktionen, die wir gerade gelernt haben
- Fällt Ihnen etwas Ungewöhnliches auf?
2.3 Fehlende Werte
- Die Datentransformation bezieht sich auf die “Korrektur” unserer Daten, wenn sie nicht “ordentlich” sind.
- in unserem
df_studentsDatenrahmen habt ihr vielleicht einigeNAoderN/AWerte bemerktN/Awurde als Text geschrieben und wird daher von R als solcher gelesen.NAin R bezieht sich auf fehlende Daten (EN:NotAvailable = DE: “Nicht verfügbar”)
- letzte Woche haben wir einige Warnmeldungen gesehen, als wir unsere Streudiagramme erstellt haben
- Diese Warnungen informierten uns über fehlende Werte (
NAs), die nicht geplottet wurden
- Diese Warnungen informierten uns über fehlende Werte (
- Echte fehlende Werte sind völlig leer, so dass die Angabe
N/Ain unserendf_students-Daten nicht wirklich als fehlender Wert gelesen wird. - Um dies zu beheben, können wir das Argument
na =für die Funktionread_csv()verwenden- Dieses Argument teilt
read_csv()mit, welche Werte mit fehlenden Werten gleichgesetzt werden sollen.
- Dieses Argument teilt
df_students <- read_csv(here::here("daten", "students.csv"),
na = "N/A")
head(df_students)# A tibble: 6 × 5
`Student ID` `Full Name` favourite.food mealPlan AGE
<dbl> <chr> <chr> <chr> <chr>
1 1 Sunil Huffmann Strawberry yoghurt Lunch only "4"
2 2 Barclay Lynn French fries Lunch only "5"
3 3 Jayendra Lyne <NA> Breakfast and lunch "7"
4 4 Leon Rossini Anchovies Lunch only ""
5 5 Chidiegwu Dunkel Pizza Breakfast and lunch "five"
6 6 Güvenç Attila Ice cream Lunch only "6"
- jetzt wird der Wert, der vorher
N/Awar, alsNAgelesen- aber was ist mit der leeren Zelle?
- Wir haben jetzt überschrieben, dass
read_csv()leere Zellen alsNAliest.- Wie können wir
read_csv()anweisen, mehr als eine Art von Eingabe alsNAzu lesen? - d.h. wir wollen, dass es
""und"N/A"x alsNAliest
- Wie können wir
df_students <- read_csv(here::here("daten", "students.csv"),
na = c("N/A",""))
head(df_students)# A tibble: 6 × 5
`Student ID` `Full Name` favourite.food mealPlan AGE
<dbl> <chr> <chr> <chr> <chr>
1 1 Sunil Huffmann Strawberry yoghurt Lunch only 4
2 2 Barclay Lynn French fries Lunch only 5
3 3 Jayendra Lyne <NA> Breakfast and lunch 7
4 4 Leon Rossini Anchovies Lunch only <NA>
5 5 Chidiegwu Dunkel Pizza Breakfast and lunch five
6 6 Güvenç Attila Ice cream Lunch only 6
2.4 Spaltennamen
- Wenn wir
df_studentsin der Konsole ausgeben, werden wir sehen, dass die ersten beiden Spaltennamen von Backticks umgeben sind (z.B.`Student ID`)- Das liegt daran, dass sie ein Leerzeichen enthalten, das syntaktisch nicht gültig ist (Variablennamen müssen mit einem Buchstaben beginnen und dürfen keine Leer- oder Sonderzeichen enthalten).
- eine schnelle Lösung ist die Funktion
clean_names()aus dem Paketjanitor
janitor::clean_names(df_students)# A tibble: 6 × 5
student_id full_name favourite_food meal_plan age
<dbl> <chr> <chr> <chr> <chr>
1 1 Sunil Huffmann Strawberry yoghurt Lunch only 4
2 2 Barclay Lynn French fries Lunch only 5
3 3 Jayendra Lyne <NA> Breakfast and lunch 7
4 4 Leon Rossini Anchovies Lunch only <NA>
5 5 Chidiegwu Dunkel Pizza Breakfast and lunch five
6 6 Güvenç Attila Ice cream Lunch only 6
- Das sieht besser aus!
- aber wenn wir jetzt
head(df_students)ausführen, sehen wir dann die bereinigten Spaltennamen?
- aber wenn wir jetzt
- Wenn wir ein Objekt durch eine Funktion übergeben, wird das Objekt nicht “aktualisiert”.
- so müssen wir das Objekt erneut zuweisen
df_students <- janitor::clean_names(df_students)- aber wir wissen oft, dass wir mehrere Funktionen (
read_csv(),clean_names()) auf demselben Objekt ausführen wollen- können wir das mit Pipes tun
2.5 Pipes
- Pipes werden am Ende eines Funktionsaufrufs gesetzt, wenn das Ergebnis dieser Funktion durch eine nachfolgende Funktion weitergegeben werden soll
- sie können als “und dann…” gelesen werden
read_csv(here::here("daten", "students.csv")) %>%
head()# A tibble: 6 × 5
`Student ID` `Full Name` favourite.food mealPlan AGE
<dbl> <chr> <chr> <chr> <chr>
1 1 Sunil Huffmann Strawberry yoghurt Lunch only 4
2 2 Barclay Lynn French fries Lunch only 5
3 3 Jayendra Lyne N/A Breakfast and lunch 7
4 4 Leon Rossini Anchovies Lunch only <NA>
5 5 Chidiegwu Dunkel Pizza Breakfast and lunch five
6 6 Güvenç Attila Ice cream Lunch only 6
- Es gibt derzeit 2 Pipes, die in R verwendet werden können
- die
magrittr-Paket-Pipe:%>% - die neue native R-Pipe:
|>
- die
- Bis jetzt habe ich noch keinen großen Unterschied zwischen den beiden entdeckt, aber im Moment bleibe ich bei
%>%
Beispiel 3
- Ladet den
students.csv-Datensatz erneut mit festenNAs und dann- Benutze eine Pipe, um
clean_names()auf dem Datensatz aufzurufen, und dann - Ruft man die Funktion
head()auf
- Benutze eine Pipe, um
- Ladet den Datensatz
students.csverneut mit festenNAs und speichert ihn als Objektdf_students, und dann- Verwendet eine Pipe, um
clean_names()auf den Datensatz anzuwenden
- Verwendet eine Pipe, um
- Warum sollte man nicht eine Pipe und die Funktion
head()verwenden, wenn man den Datensatz als Objekt speichert?
2.6 Andere Dateitypen
- Sobald wir mit
read_csv()vertraut sind, sind die anderen Funktionen vonreadreinfach zu benutzen- man muss nur wissen, wann man welche benutzt
read_csv2()liest Semikolon-getrennte Dateien- Diese verwenden
;anstelle von,zur Trennung von Feldern und sind in Ländern üblich, die,als Dezimalzeichen verwenden
- Diese verwenden
read_tsv()liest Tabulator-getrennte Dateienread_delim()liest Dateien mit beliebigen Begrenzungszeichen ein- versucht, das Trennzeichen zu erraten
- es sei denn, ihr gebt es mit dem Argument
delim =an (z. B.read_delim("students.csv", delim = ","))
Andere habe ich noch nicht gebraucht:
read_fwf()liest Dateien mit fester Breiteread_table()liest eine gängige Variante von Dateien mit fester Breite, bei der die Spalten durch Leerzeichen getrennt sindread_log()liest Log-Dateien im Apache-Stil
Beispiel 4
- Welche Funktion wird verwendet, um eine Datei zu lesen, deren Felder durch
|getrennt sind? - Welche Argumente haben
read_csv()undread_tsv()gemeinsam? - Wie würdet ihr einen Datensatz mit einem Semikolon als Begrenzungszeichen einlesen?
- Ladet den Datensatz
nettle_1999_climate.csvein- wie viele Variablen gibt es?
- Ladet den Datensatz
nettle_1999_climate2.csvein- Wie viele Variablen gibt es? Ist das richtig?
- Ladet den Datensatz
nettle_1999_climate3.csvein- wie viele Variablen sind vorhanden? Ist dies richtig?
3 Dateneingabe
wenn wir kleine Datenmengen sammeln, möchten wir sie vielleicht von Hand in R eingeben
- Es gibt zwei nützliche Funktionen, die uns dabei helfen, gesammelte Daten zu nehmen und ein “Tibble” zu erstellen
tibbles sind moderne Datenrahmen, macht euch noch keine Gedanken über die Definition eines TibblesSammeln wir die Initialen, die Körpergröße (cm) und das Geburtsdatum (ttmm) von allen
i <- "DP" # a "string"
h <- 171 # a number
m <- 05 # a number
d <- 073.1 tibble()
tibble(
initial = i,
height = h,
month = "Mai",
day = 7)# A tibble: 1 × 4
initial height month day
<chr> <dbl> <chr> <dbl>
1 DP 171 Mai 7
3.2 tribble()
- es könnte einfacher sein, die Daten Zeile für Zeile einzugeben
- dies ist mit einem transponierten Tibble (
Tribble) möglich
- dies ist mit einem transponierten Tibble (
tribble(
~initial, ~height, ~month, ~day,
"DP", 171, 07, 05
)# A tibble: 1 × 4
initial height month day
<chr> <dbl> <dbl> <dbl>
1 DP 171 7 5
Beispiel 5
- Speichert das Tibble (d.h. den Datenrahmen) als das Objekt
df_wir. - Den Datensatz untersuchen (z.B. Zusammenfassungen drucken)
- Was kommt Ihnen seltsam vor?
initial height month day
Length:1 Min. :171 Min. :5 Min. :7
Class :character 1st Qu.:171 1st Qu.:5 1st Qu.:7
Mode :character Median :171 Median :5 Median :7
Mean :171 Mean :5 Mean :7
3rd Qu.:171 3rd Qu.:5 3rd Qu.:7
Max. :171 Max. :5 Max. :7
4 Arbeiten mit Variablen
- In einem Datenrahmen sind die Variablen in Spalten organisiert
4.1 Variablentypen
readrerrät den Typ der Daten, die jede Spalte enthält- Die wichtigsten Spaltentypen, die man kennen sollte, sind
numerischundkategorisch(=factor).
- Die wichtigsten Spaltentypen, die man kennen sollte, sind
factors enthalten Kategorien oder Gruppen von Daten, können aber manchmal wienumerischeDaten aussehen.- Unsere Spalte
monthenthält zum Beispiel Zahlen, aber sie kann auch den Namen jedes Monats enthalten. - Es ist sinnvoll, den Mittelwert einer
numerischenVariable zu berechnen, aber nicht den einesfactors.- Es ist sinnvoll, den Mittelwert der Körpergröße zu berechnen, aber nicht den Mittelwert des Geburtsmonats.
- Unsere Spalte
df_wir$month <- as_factor(df_wir$month)4.2 Indizierung
- manchmal wollen wir auf eine bestimmte Variable (Spalte) in einem Datenrahmen zugreifen
- Bei Verwendung von Base R tun wir das mit
$:Datenrahmen$Variable
- Bei Verwendung von Base R tun wir das mit
df_wir$height[1] 171
- und wir können dies als Argument für eine Funktion verwenden
- Versuche, die minimale und maximale Höhe in unserer Gruppe zu finden.
- die Summe (EN:
sum) unserer Höhen berechnen
Beispiel 6
- Umrechnung von
df_wir$monthin einen Faktor - Berechne unsere mittlere Höhe mit der Funktion
mean()und der Indizierung - Berechne die Summe unserer Höhen.
4.3 In Datei schreiben
- wir können unseren Datenrahmen auch speichern, so dass wir später darauf zurückkommen können mit
write_csv(object_name, "desired_filename.csv")- oder, mit
here:write_csv(object_name, here::here("ordner", "desired_filename.csv"))
- oder, mit
- Seid sehr vorsichtig! Wenn ihr einen existierenden Dateinamen verwendet, könnt ihr einen bereits existierenden Datensatz überschreiben
write_csv(df_wir, file = here("daten", "wir.csv"))5 Übungen
Hier findet ihr einige vertiefende Übungen.
5.1 Import/Export
- Ladet den eingebauten
starwars-Datensatz, der Informationen über Star Wars Charaktere enthält. - Exportiert die Daten als
csvDatei mit dem Namenstarwarsin eurendatenOrdner. - Importiere die
starwars.csvDatei mitread_csv().
5.2 Spaltentypen konvertieren
- Konvertiere die folgenden Variablen in Faktoren:
hair_colorskin_coloreye_colorsexgenderhomeworldspecies
5.3 Plots
Erstellt die folgenden drei Diagramme und beschreibt kurz, was sie zeigen und welche Schlussfolgerungen daraus gezogen werden können.
Erstellt ein weiteres Diagramm eurer Wahl aus dem “Starwars”-Datensatz. Fügt sie in das Diagrammgitter ein (ihr müsst die Syntax anpassen). Beschreibt was sie zeigt.
(fig_sw_height + fig_sw_gender) /
fig_sw_height_mass +
plot_layout(nrow = 2, heights = c(.4,.6)) +
plot_annotation(
title = "Some plots using the `starwars` dataset",
subtitle = "Each plot visualises different variables",
tag_levels = "A")Heutige Ziele 🏁
Heute haben wir…
- gelernt, wie man einen neuen Datensatz in Augenschein nimmt ✅
- gelernt, wie man verschiedene Datentypen importiert ✅
- gelernt, wie man Daten von Hand eingibt ✅
- einen neuen Datensatz visualisiert ✅
Session Info
Hergestellt mit R version 4.2.3 (2023-03-15) (Shortstop Beagle) und RStudioversion 2023.3.0.386 (Cherry Blossom).
sessionInfo()R version 4.2.3 (2023-03-15)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.2.1
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] kableExtra_1.3.4 patchwork_1.1.2 here_1.0.1 janitor_2.2.0
[5] lubridate_1.9.2 forcats_1.0.0 stringr_1.5.0 dplyr_1.1.1
[9] purrr_1.0.1 readr_2.1.4 tidyr_1.3.0 tibble_3.2.1
[13] ggplot2_3.4.2 tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] svglite_2.1.1 rprojroot_2.0.3 digest_0.6.31 utf8_1.2.3
[5] R6_2.5.1 evaluate_0.20 httr_1.4.5 highr_0.10
[9] pillar_1.9.0 rlang_1.1.0 rstudioapi_0.14 rmarkdown_2.21
[13] labeling_0.4.2 webshot_0.5.4 htmlwidgets_1.6.2 bit_4.0.5
[17] munsell_0.5.0 compiler_4.2.3 xfun_0.38 pkgconfig_2.0.3
[21] systemfonts_1.0.4 htmltools_0.5.5 tidyselect_1.2.0 fansi_1.0.4
[25] viridisLite_0.4.1 crayon_1.5.2 tzdb_0.3.0 withr_2.5.0
[29] grid_4.2.3 jsonlite_1.8.4 gtable_0.3.3 lifecycle_1.0.3
[33] pacman_0.5.1 magrittr_2.0.3 scales_1.2.1 cli_3.6.1
[37] stringi_1.7.12 vroom_1.6.1 farver_2.1.1 snakecase_0.11.0
[41] xml2_1.3.3 generics_0.1.3 vctrs_0.6.1 RColorBrewer_1.1-3
[45] tools_4.2.3 bit64_4.0.5 glue_1.6.2 hms_1.1.3
[49] parallel_4.2.3 fastmap_1.1.1 yaml_2.3.7 timechange_0.2.0
[53] colorspace_2.1-0 rvest_1.0.3 knitr_1.42